#!/usr/bin/env python
# -*- coding: utf-8 -*-

__author__ = 'baixue'


from ctypes import *


adk_lib = windll.LoadLibrary('8144.dll')


#------------------System & Initialization-------------------#
def initial(ManualId=0):
    cardId = c_int()
    manualId = c_short(ManualId)
    err = adk_lib._8144_initial(byref(cardId), manualId)
    check_error(err)
    return cardId.value

def close():
    err = adk_lib._8144_close()
    check_error(err)
    return None

def get_version(CardId):
    cardId = c_short(CardId)
    dll_1 = c_int()
    dll_2 = c_int()
    firmwareVersion = c_int()
    driverVersion = c_int()
    err = adk_lib._8144_get_version(cardId, byref(dll_1), byref(dll_2, byref(firmwareVersion), byref(driverVersion)))
    check_error(err)
    return (dll_1.value, dll_2.value, firmwareVersion.value, driverVersion.value)

def set_security_key(CardId, OldPassword, NewPassword):
    cardId = c_short(CardId)
    oldPwd = c_short(OldPassword)
    newPwd = c_short(NewPassword)
    err = adk_lib._8144_set_security_key(cardId, oldPwd, newPwd)
    check_error(err)
    return None

def check_security_key(CardId, Password):
    cardId = c_short(CardId)
    pwd = c_short(Password)
    err = adk_lib._8144_check_security_key(cardId, pwd)
    check_error(err)
    return None

def reset_security_key(CardId):
    cardId = c_short(CardId)
    err = adk_lib._8144_reset_security_key(cardId)
    check_error(err)
    return None

#------------------Motion Interface I/O-------------------#
def set_limit_logic(AxisNo, LimitLogic):
    axisNo = c_short(AxisNo)
    limitLogic = c_short(LimitLogic)
    err = adk_lib._8144_set_limit_logic(axisNo, limitLogic)
    check_error(err)
    return None

def get_limit_logic(AxisNo):
    axisNo = c_short(AxisNo)
    limitLogic = c_short()
    err = adk_lib._8144_get_limit_logic(axisNo, byref(limitLogic))
    check_error(err)
    return limitLogic.value

def get_mio_status(AxisNo):
    axisNo = c_short(AxisNo)
    motionIoStatusInBit = c_short()
    err = adk_lib._8144_get_mio_status(axisNo, byref(motionIoStatusInBit))
    check_error(err)
    return motionIoStatusInBit.value

def set_mio_sensitivity(AxisNo, HighOrLow):
    axisNo = c_short(AxisNo)
    highOrLow = c_short(HighOrLow)
    err = adk_lib._8144_set_mio_sensitivity(axisNo, highOrLow)
    check_error(err)
    return None

def set_pls_outmode(AxisNo, PulseLogic):
    axisNo = c_short(AxisNo)
    pulseLogic = c_short(PulseLogic)
    err = adk_lib._8144_set_pls_outmode(axisNo, pulseLogic)
    check_error(err)
    return None

def set_pls_outmode2(AxisNo, PulseMode, PulseLogic):
    axisNo = c_short(AxisNo)
    pulseMode = c_short(PulseMode)
    pulseLogic = c_short(PulseLogic)
    err = adk_lib._8144_set_pls_outmode2(axisNo, pulseMode, pulseLogic)
    check_error(err)
    return None

#------------------Motion-------------------#
def tv_move(AxisNo, StrVel, MaxVel, Tacc):
    axisNo = c_short(AxisNo)
    strVel = c_double(StrVel)
    maxVel = c_double(MaxVel)
    tacc = c_double(Tacc)
    err = adk_lib._8144_tv_move(axisNo, strVel, maxVel, tacc)
    check_error(err)
    return None

def sv_move(AxisNo, StrVel, MaxVel, TSacc):
    axisNo = c_short(AxisNo)
    strVel = c_double(StrVel)
    maxVel = c_double(MaxVel)
    tsacc = c_double(TSacc)
    err = adk_lib._8144_sv_move(axisNo, strVel, maxVel, tsacc)
    check_error(err)
    return None

def start_tr_move(AxisNo, Distance, StrVel, MaxVel, Tacc):
    axisNo = c_short(AxisNo)
    distance = c_double(Distance)
    strVel = c_double(StrVel)
    maxVel = c_double(MaxVel)
    tacc = c_double(Tacc)
    err = adk_lib._8144_start_tr_move(axisNo, distance, strVel, maxVel, tacc)
    check_error(err)
    return None

def start_sr_move(AxisNo, Distance, StrVel, MaxVel, TSacc):
    axisNo = c_short(AxisNo)
    distance = c_double(Distance)
    strVel = c_double(StrVel)
    maxVel = c_double(MaxVel)
    tsacc = c_double(TSacc)
    err = adk_lib._8144_start_sr_move(axisNo, distance, strVel, maxVel, tsacc)
    check_error(err)
    return None

def emg_stop(AxisNo):
    axisNo = c_short(AxisNo)
    err = adk_lib._8144_emg_stop(axisNo)
    check_error(err)
    return None

def dec_stop(AxisNo):
    axisNo = c_short(AxisNo)
    err = adk_lib._8144_dec_stop(axisNo)
    check_error(err)
    return None

def slow_down(AxisNo):
    axisNo = c_short(AxisNo)
    err = adk_lib._8144_slow_down(axisNo)
    check_error(err)
    return None

def speed_up(AxisNo):
    axisNo = c_short(AxisNo)
    err = adk_lib._8144_speed_up(axisNo)
    check_error(err)
    return None

def enable_org_stop(AxisNo, Enable):
    axisNo = c_short(AxisNo)
    enable = c_short(Enable)
    err = adk_lib._8144_enable_org_stop(axisNo, enable)
    check_error(err)
    return None

def enable_sd_signal(AxisNo, Enable):
    axisNo = c_short(AxisNo)
    enable = c_short(Enable)
    err = adk_lib._8144_enable_sd_signal(axisNo, enable)
    check_error(err)
    return None

def get_remaining_pulse(AxisNo):
    axisNo = c_short(AxisNo)
    remainingPulse = c_double()
    err = adk_lib._8144_get_remaining_pulse(axisNo, byref(remainingPulse))
    check_error(err)
    return remainingPulse.value

def set_remaining_pulse(AxisNo, RemainingPulse):
    axisNo = c_short(AxisNo)
    remainingPulse = c_double(RemainingPulse)
    err = adk_lib._8144_set_remaining_pulse(axisNo, remainingPulse)
    check_error(err)
    return None

def get_command(AxisNo):
    axisNo = c_short(AxisNo)
    cmd = c_int()
    err = adk_lib._8144_get_command(axisNo, byref(cmd))
    check_error(err)
    return cmd.value

def set_command(AxisNo, Cmd):
    axisNo = c_short(AxisNo)
    cmd = c_int(Cmd)
    err = adk_lib._8144_set_command(axisNo, cmd)
    check_error(err)
    return None

def get_position(AxisNo):
    axisNo = c_short(AxisNo)
    pos = c_double()
    err = adk_lib._8144_get_position(axisNo, byref(pos))
    check_error(err)
    return pos.value

#------------------Motion status-------------------#
def motion_done(AxisNo):
    axisNo = c_short(AxisNo)
    operationOrStop = c_short()
    err = adk_lib._8144_motion_done(axisNo, byref(operationOrStop))
    check_error(err)
    return operationOrStop.value

def motion_status(AxisNo):
    axisNo = c_short(AxisNo)
    motionStatusInBit = c_short()
    err = adk_lib._8144_motion_status(axisNo, byref())
    check_error(err)
    return motionStatusInBit.value

#------------------Interrupt-------------------#
def set_motion_interrupt_factor(AxisNo, MotionIntFactorInBit):
    axisNo = c_short(AxisNo)
    motionIntFactorInBit = c_short(MotionIntFactorInBit)
    err = adk_lib._8144_set_motion_interrupt_factor(axisNo, motionIntFactorInBit)
    check_error(err)
    return None

def set_gpio_interrupt_factor(CardId, GpioIntFactorInBit):
    cardId = c_short(CardId)
    gpioIntFactorInBit = c_int(GpioIntFactorInBit)
    err = adk_lib._8144_set_gpio_interrupt_factor(cardId, gpioIntFactorInBit)
    check_error(err)
    return None

def wait_single_motion_interrupt(AxisNo, MotionIntFactorBitNum, TimeOutMs):
    axisNo = c_short(AxisNo)
    motionIntFactorBitNum = c_short(MotionIntFactorBitNum)
    timeOutMs = c_int(TimeOutMs)
    err = adk_lib._8144_wait_single_motion_interrupt(axisNo, motionIntFactorBitNum, timeOutMs)
    check_error(err)
    return None

def wait_single_gpio_interrupt(CardId, GpioIntFactorBitNum, TimeOutMs):
    cardId = c_short(CardId)
    gpioIntFactorInBitNum = c_int(GpioIntFactorInBitNum)
    timeOutMs = c_int(TimeOutMs)
    err = adk_lib._8144_wait_single_gpio_interrupt(cardId, gpioIntFactorInBitNum, timeOutMs)
    check_error(err)
    return None

def wait_multiple_gpio_interrupt(CardId, GpioIntFactorInBits, WaitOption, TimeOutMs):
    cardId = c_short(CardId)
    gpioIntFactorInBits = c_int(GpioIntFactorInBits)
    waitOption = c_short(WaitOption)
    timeOutMs = c_int(TimeOutMs)
    gpioIntTriggeredInBits = c_int()
    err = adk_lib._8144_wait_multiple_gpio_interrupt(cardId, gpioIntFactorInBits, waitOption, timeOutMs, byref(gpioIntTriggeredInBits))
    check_error(err)
    return gpioIntTriggeredInBits.value

#------------------General purpose I/O-------------------#
def get_gpio_input(CardId):
    cardId = c_short(CardId)
    DiStatusInBit = c_short()
    err = adk_lib._8144_get_gpio_input(cardId, byref(DiStatusInBit))
    check_error(err)
    return DiStatusInBit.value

def get_gpio_input_channel(CardId, ChannelNum):
    cardId = c_short(CardId)
    channelNum = c_short(ChannelNum)
    diStatus = c_short()
    err = adk_lib._8144_get_gpio_input_channel(cardId, byref(diStatus))
    check_error(err)
    return diStatus.value

def get_gpio_output(CardId):
    cardId = c_short(CardId)
    doValueInBit = c_short()
    err = adk_lib._8144_get_gpio_output(cardId, byref(doValueInBit))
    check_error(err)
    return doValueInBit.value

def get_gpio_output_channel(CardId, ChannelNum):
    cardId = c_short(CardId)
    channelNum = c_short(ChannelNum)
    doValue = c_short()
    err = adk_lib._8144_get_gpio_output_channel(cardId, channelNum, byref(doValue))
    check_error(err)
    return doValue.value

def set_gpio_output(CardId, DoValueInBit):
    cardId = c_short(CardId)
    doValueInBit = c_short(DoValueInBit)
    err = adk_lib._8144_set_gpio_output(cardId, doValueInBit)
    check_error(err)
    return None

def set_gpio_output_channel(CardId, ChannelNum, DoValue):
    cardId = c_short(CardId)
    channelNum = c_short(ChannelNum)
    doValue = c_short(DoValue)
    err = adk_lib._8144_set_gpio_output_channel(cardId, channelNum, doValue)
    check_error(err)
    return None

#------------------Speed profile calculation-------------------#
def get_tv_move_profile(AxisNo, StrVel, MaxVel, Tacc):
    axisNo = c_short(AxisNo)
    strVel = c_double(StrVel)
    maxVel = c_double(MaxVel)
    tacc = c_double(Tacc)
    strVelP = c_double()
    maxVelP = c_double()
    taccP = c_double()
    magnP = c_double()
    err = adk_lib._8144_get_tv_move_profile(axisNo, strVel, maxVel, tacc, byref(strVelP), byref(maxVelP), byref(taccP), byref(magnP))
    check_error(err)
    return (strVelP.value, maxVelP.value, taccP.value,magnP.value)

def get_sv_move_profile(AxisNo, StrVel, MaxVel, Tacc):
    axisNo = c_short(AxisNo)
    strVel = c_double(StrVel)
    maxVel = c_double(MaxVel)
    tacc = c_double(Tacc)
    strVelP = c_double()
    maxVelP = c_double()
    taccP = c_double()
    magnP = c_double()
    err = adk_lib._8144_get_sv_move_profile(axisNo, strVel, maxVel, tacc, byref(strVelP), byref(maxVelP), byref(taccP), byref(magnP))
    check_error(err)
    return (strVelP.value, maxVelP.value, taccP.value,magnP.value)

def get_start_tr_move_profile(AxisNo, Distance, StrVel, MaxVel, Tacc):
    axisNo = c_short(AxisNo)
    strVel = c_double(StrVel)
    maxVel = c_double(MaxVel)
    tacc = c_double(Tacc)
    strVelP = c_double()
    maxVelP = c_double()
    taccP = c_double()
    tConstP = c_double()
    tDecP = c_double()
    magnP = c_double()
    err = adk_lib._8144_get_start_tr_move_profile(axisNo, strVel, maxVel, tacc, byref(strVelP), byref(maxVelP), byref(taccP), byref(tConstP), byref(tDecP),byref(magnP))
    check_error(err)
    return (strVelP.value, maxVelP.value, taccP.value, tConstP.value, tDecP.value, magnP.value)

def get_start_sr_move_profile(AxisNo, Distance, StrVel, MaxVel, Tacc):
    axisNo = c_short(AxisNo)
    strVel = c_double(StrVel)
    maxVel = c_double(MaxVel)
    tacc = c_double(Tacc)
    strVelP = c_double()
    maxVelP = c_double()
    taccP = c_double()
    tConstP = c_double()
    tDecP = c_double()
    magnP = c_double()
    err = adk_lib._8144_get_start_sr_move_profile(axisNo, strVel, maxVel, tacc, byref(strVelP), byref(maxVelP), byref(taccP), byref(tConstP), byref(tDecP),byref(magnP))
    check_error(err)
    return (strVelP.value, maxVelP.value, taccP.value, tConstP.value, tDecP.value, magnP.value)

#------------------Motion advance-------------------#
def one_axis_move(AxisNo, MotionType, SpeedPattern, Direction,  AccDecCurveType, R0_PE, R1_FL, R2_FH, R3_AC, R4_MA, R5_RD):
    axisNo = c_short(AxisNo)
    motionType = c_ushort(MotionType)
    speedPattern = c_ushort(SpeedPattern)
    direction = c_ushort(Direction)
    accDucCurveType = c_ushort(AccDecCurveType)
    R0_PE = c_int(R0_PE)
    R1_FL = c_ushort(R1_FL)
    R2_FH = c_ushort(R2_FH)
    R3_AC = c_ushort(R3_AC)
    R4_MA = c_ushort(R4_MA)
    R5_RD = c_ushort(R5_RD)
    err = adk_lib._8144_one_axis_move(AxisNo, motionType, speedPattern, direction,  accDecCurveType, R0_PE, R1_FL, R2_FH, R3_AC, R4_MA, R5_RD)
    check_error(err)
    return None

#------------------Error Code Def-------------------#
ErrorMsg = ("ERR_OSVersion",
            "ERR_OpenDriverFailed",
            "ERR_InsufficientMemory",
            "ERR_DeviceNotInitial",
            "ERR_NoDeviceFound",
            "ERR_CardIdDuplicate",
            "ERR_DeviceAlreadyInitialed",
            "ERR_InterruptNotEnable",
            "ERR_TimeOut",
            "ERR_ParametersInvalid",
            "ERR_SetEEPROM",
            "ERR_GetEEPROM",
            "ERR_MotionBusy"
            )

WarningMsg = ("WAR_AccDecTimeTooLarge",
              "WAR_AccDecTimeTooSmall",
              "WAR_RampDownPointExceed",
              "WAR_DistanceTooShort"
              )

ERR_Win32Error = -1000

class Adk_Error(Exception):
    def __init__(self, errcode):
        self.errcode = errcode

    def __str__(self):
        if self.errcode in (1,2,3,4):
            return WarningMsg[self.errcode-1]
        elif self.errcode >= -13 and self.errcode <= -1:
            return ErrorMsg[-self.errcode-1]
        else:
            return "Win32Error:{}".format(str(-(self.errcode + ERR_Win32Error)))


def check_error(errcode):
    if errcode != 0:
        raise Adk_Error(errcode)

